from level_editor_hud import LevelEditorHud
from panda3d.core import Vec2, Point3, Vec3, Vec4, BitMask32
from picker import Picker
from visual_object_3D import *
import os
from object_const import ObjectConstants
'''
	Andrew Oberlin
	Date: March 3, 2012
'''
class LevelEditor:
	MAX_WIDTH = 96
	MAX_HEIGHT = 128
	BLOCK_SIZE = 5
	'''
		Constructor for the Level Editor
	'''
	def __init__(self, parent):
		self.parent = parent
		self.levelEditorHud = LevelEditorHud(parent, self)
		self.const = ObjectConstants()
		self.mapDummy = self.parent.render.attachNewNode('map_dummy')
		self.terrainDummy = self.mapDummy.attachNewNode('terrain_dummy')
		self.clickToPlace = False
		self.models = list()
		
		self.map = [[None for i in range(self.MAX_HEIGHT)] for j in range(self.MAX_WIDTH)]
		
		for i in range(self.MAX_WIDTH):
			for j in range(self.MAX_HEIGHT):
				self.map[i][j] = self.loadModel(self.const.SAND)
				self.map[i][j].setScale(self.BLOCK_SIZE)
				self.map[i][j].setPos((i - self.MAX_WIDTH/2.0)*self.BLOCK_SIZE, 0, (j - self.MAX_HEIGHT/2.0)*self.BLOCK_SIZE)
				self.map[i][j].setCollideMask(BitMask32(0x01))
		
		self.objectModel = VisualObject3D(self.parent, self.mapDummy, 'object_model')
		self.commandCenter = None
		
		self.parent.taskMgr.add(self.addModelTask, 'objectModelWatcher')
		
		self.selectedSquare = self.loadModel('select')
		self.selectedSquare.setScale(self.BLOCK_SIZE)
		self.selectedSquare.reparentTo(self.mapDummy)
		
		self.selectedSquare.hide()
		
		self.picker = Picker(fromMask=BitMask32(0x01), collideWithGeom=True)
		self.parent.accept("mouse1", self.pick, [False])
		self.parent.accept("mouse3", self.pick, [True])
		self.selected = None
		
		
		self.parent.accept("escape", self.letGo)
		
	'''
		Loads the correct item as a model and as a texture
	'''
	def loadModel(self, switch):
		texture = self.const.getTextureFromNo(switch, tuple=False)
		if (texture == "" and switch == 'select'):
			texture = "models/menu/hud/select.png"

		model = self.parent.loader.loadModelCopy("models/plane")
		texture = self.parent.loader.loadTexture(texture)
		model.setTexture(texture)
		model.setTransparency(1)
		model.reparentTo(self.terrainDummy)
		
		return model
		
	def pick(self, rightClick):
		cEntry = self.picker.pick(traverseRoot=self.terrainDummy)
		if cEntry:
			if (self.selected != None):
				self.unselect()
			geomHit = cEntry.getIntoNodePath()
			if (geomHit != self.selected):
				self.selected = geomHit.getParent().getParent()
				self.select(rightClick)
			
	def unselect(self):
		self.selectedSquare.hide()
	
	def select(self, rightClick):
		self.selectedSquare.show()
		self.selectedSquare.setPos(self.selected.getPos() + Vec3(0,-0.05,0))
		if (rightClick):
			texture = self.levelEditorHud.getSelection()
			if (texture[0] == self.const.TEXTURE and self.parent.levelEditor.selected):
				self.selected.setTexture(texture[1])
	
	def placeObjectModel(self):
		selection = self.levelEditorHud.getSelection()
		cEntry = self.picker.pick(traverseRoot=self.terrainDummy)
		if cEntry:
			commandCenter = False
			newModel = self.const.getObjectFromTexture(str(selection[1].getFilename()), self.parent, self.mapDummy)
			if (str(selection[1].getFilename()) == self.const.getTextureFromNo(self.const.COMMAND_CENTER, tuple=False)):
				commandCenter = True
			if (newModel):
				newModel.setPos(cEntry.getSurfacePoint(self.mapDummy)
					+ Vec3(0,-newModel.height/2, 0))
				if (not commandCenter):
					self.models.append(newModel)
				else:
					if (self.commandCenter):
						self.commandCenter.removeNode()
					self.commandCenter = newModel
	
	def addModelTask(self, task):
		selection = self.levelEditorHud.getSelection()
		if (selection[0] == self.const.OBJECT):
			if (not self.clickToPlace):
				self.clickToPlace = True
				self.parent.ignore("mouse1")
				self.parent.accept("mouse1", self.placeObjectModel)
			if (selection[1] is not self.objectModel.getTexture()):
				self.objectModel.removeNode()
				self.objectModel = self.const.getObjectFromTexture(str(selection[1].getFilename()), self.parent, self.mapDummy)
			cEntry = self.picker.pick(traverseRoot=self.terrainDummy)
			if cEntry:
				self.objectModel.setPos(cEntry.getSurfacePoint(self.mapDummy)
					+ Vec3(0,-self.objectModel.height/2, 0))
		elif (self.clickToPlace == True):
				self.clickToPlace = False
				self.parent.ignore("mouse1")
				self.parent.accept("mouse1", self.pick, [False])
		return task.cont
	
	def exit(self):
		self.destroyMap()
		self.parent.mainMenu.show()
		
		
	def save(self, filename, levelName):
		if (self.commandCenter):
			if (os.path.exists("maps/" + filename + ".lvl")):
				os.remove("maps/" + filename + ".lvl")
			saveFile = open("maps/" + filename + ".lvl", 'w')
			
			saveFile.write(levelName + "\n")

			saveFile.write("#command_center\n")
			saveFile.write(str(self.commandCenter.getX()) + " " + str(self.commandCenter.getY()) + " " + str(self.commandCenter.getZ()) + "\n")
			
			saveFile.write("#map\n")
			
			for (counter, row) in enumerate(self.map):
				if counter != 0:
					saveFile.write("\n")
				for col in row:
					textureNo = self.const.getNoFromTexture(
						str(col.getTexture().getFilename())
					)
					saveFile.write(str(textureNo) + " ")
			
			saveFile.write("\n#models\n")
			
			for model in self.models:
				textureNo = self.const.getNoFromTexture(model.textureFile)
				pos = model.getPos()
				
				saveFile.write(str(textureNo) + " " + str(pos[0]) + " " 
					+ str(pos[1]) + " " + str(pos[2]) + "\n")
				
			saveFile.close()
		
	def load(self, filename):
		if (os.path.exists("maps/" + filename + ".lvl")):
			loadFile = open("maps/" + filename + ".lvl", 'r')
			self.destroyMap(destroyHud=False)
			
			mapFound = False
			modelsFound = False
			commandCenterFound = False
			i = 0
			for line in loadFile:
				if (line == "#command_center\n"):
					commandCenterFound = True
				elif (line == "#map\n"):
					mapFound = True
					i = -1
				elif (line == "#models\n"):
					modelsFound = True
				elif (commandCenterFound and not mapFound and not modelsFound):
					obj = line.split(" ")
					newModel = self.const.getObjectFromNo(self.const.COMMAND_CENTER, self.parent, self.mapDummy)
					newModel.setPos(Vec3(float(obj[0]), float(obj[1]), float(obj[2])))
					self.commandCenter = newModel
					self.models.append(newModel)
				elif (mapFound and commandCenterFound and not modelsFound):
					row = line.split(" ")
					for (j, cell) in enumerate(row):
						try:
							self.map[i][j] = self.loadModel(int(cell))
							self.map[i][j].setScale(self.BLOCK_SIZE)
							self.map[i][j].setPos((i - self.MAX_WIDTH/2.0)*self.BLOCK_SIZE, 0, (j - self.MAX_HEIGHT/2.0)*self.BLOCK_SIZE)
							self.map[i][j].setCollideMask(BitMask32(0x01))
						except ValueError:
							j -= 1
				elif(modelsFound):
					obj = line.split(" ")
					newModel = self.const.getObjectFromNo(int(obj[0]), self.parent, self.mapDummy)
					newModel.setPos(Vec3(float(obj[1]), float(obj[2]), float(obj[3])))
					self.models.append(newModel)
				i += 1
					
			
		
	def destroyMap(self, destroyHud=True):
		for row in self.map:
			for col in row:
				col.removeNode()
		
		self.map = [[None for i in range(self.MAX_HEIGHT)] for j in range(self.MAX_WIDTH)]
		
		for model in self.models:
			model.removeNode()
			
		self.models = list()
		
		if (destroyHud):
			self.objectModel.removeNode()
			self.selectedSquare.removeNode()
			self.levelEditorHud.destroy()
			
	def letGo(self):
		self.levelEditorHud.setSelection(self.const.SAND)
		self.objectModel.hide()
		
		